<?xml version="1.0" encoding="UTF-8"?>

<!-- 
        	Rules for City Public Lighting  Indicators Urban Dataset
        	Automatically generated from SCPS Ontology 2.0 on: 2026/04/27 08:56:06
-->

<schema queryBinding="xslt2" xmlns="http://purl.oclc.org/dsdl/schematron">
  <ns uri="smartcityplatform:enea:information:xml:schemas:main:urbandataset" prefix="scps"/>




  <pattern abstract="false" id="CityPublicLightingIndicators">

    <let name="UDname" value="'City Public Lighting  Indicators'"/>
    <let name="UDuri" value="'https://smartcityplatform.enea.it/specification/semantic/2.0/ontology/scps-ontology-2.0.owl#CityPublicLightingIndicators'"/>

    <let name="propertyNum" value="3"/>

    <let name="propertyDefNum" value="6"/>

    <let name="propNameList" value="'CityPLIndicatorCode IndicatorValue TownCode period end_ts start_ts'"/>

    <let name="firstLevelPropNameList" value="'CityPLIndicatorCode IndicatorValue TownCode'"/>

    <let name="propNameSet" value="tokenize('CityPLIndicatorCode, IndicatorValue, TownCode, period, end_ts, start_ts', '[,\s]+')"/>

    <let name="dataTypeSet" value="tokenize('string, double, string, complex-2, dateTime, dateTime', '[,\s]+')"/>

    <let name="umSet" value="tokenize('dimensionless, dimensionless, dimensionless, dimensionless, dimensionless, dimensionless', '[,\s]+')"/>

    <let name="codeListSet" value="tokenize('https://smartcityplatform.enea.it/specification/semantic/2.0/gc/CityPLIndicatorCode.gc, null, https://smartcityplatform.enea.it/specification/semantic/2.0/gc/TownCode.gc, null, null, null', '[,\s]+')"/>


    <let name="subPropNameSet" value="tokenize('periodend_ts, periodstart_ts', '[,\s]+')"/>


    <let name="root" value="scps:UrbanDataset"/>

    <let name="measurementType" value="tokenize('', '[,\s]+')"/>

    <let name="measurementTypeSet" value="tokenize('false, false, false, false, false, false', '[,\s]+')"/>


    <let name="propNameOcc" value="tokenize('1, 1, 1, 1, 1, 1', '[,\s]+')"/>

    <let name="umAltSet" value="tokenize('', '[,\s]+')"/>


    <let name="mandatPropPosition" value="index-of($propNameOcc, '1')"/>
    <let name="mandatPropCount" value="count(index-of($propNameOcc, '1'))"/>
    <let name="firstID" value="//scps:line[1]/@id"/>
    
    <let name="useProfileProp"
      value="distinct-values(//scps:propertyDefinition[not(scps:propertyName = 'start_ts')][not(scps:propertyName = 'end_ts')][not(scps:propertyName = 'format')][not(scps:propertyName = 'longitude')][not(scps:propertyName = 'latitude')][not(scps:propertyName = 'height')][not(scps:propertyName = 'period')][not(scps:propertyName = 'coordinates')][not(scps:propertyName = 'DataDescription')][not(scps:propertyName = 'timestamp')]/scps:propertyName)"/>
    
    <let name="useProfilePropCount" value="count($useProfileProp)"/>
    
    <let name="coordinatesCheck"
      value="(count(//scps:propertyDefinition[scps:propertyName = 'coordinates']) = 1)"/>
    <let name="periodCheck"
      value="(count(//scps:propertyDefinition[scps:propertyName = 'period']) = 1)"/>
    <let name="descrCheck"
      value="(count(//scps:propertyDefinition[scps:propertyName = 'DataDescription']) = 1)"/>
    <let name="tsCheck"
      value="(count(//scps:propertyDefinition[scps:propertyName = 'timestamp']) = 1)"/>
    
    <let name="periodOcc" value="($propNameOcc[index-of($propNameSet, 'period')] = '1')"/>
    <let name="coordinatesOcc" value="($propNameOcc[index-of($propNameSet, 'coordinates')] = '1')"/>
    <let name="descrOcc" value="($propNameOcc[index-of($propNameSet, 'DataDescription')] = '1')"/>  
    <let name="tsOcc" value="($propNameOcc[index-of($propNameSet, 'timestamp')] = '1')"/>
    
    <rule context="//scps:specification">
      <assert test="not(@version) or (@version = '2.0')" flag="fatal" id="UD-001">[UD-001]- La
        versione delle specifiche ha un valore errato; il valore dovrebbe essere '2.0'.</assert>
      <assert test="(normalize-space(scps:name) = normalize-space($UDname))" flag="fatal"
        id="UD-002">[UD-002] - Il nome dell'UrbanDataset non e' coerente con la sua specifica; il
        valore dovrebbe essere <value-of select="$UDname"/>
      </assert>
      <assert test="(normalize-space(scps:uri) = normalize-space($UDuri))" flag="fatal" id="UD-003"
        >[UD-003] - Il riferimento alla specifica dell'UrbanDataset non e' corretto.</assert>
    </rule>
    
    <rule context="//scps:properties">
      <let name="propDefCount" value="count(scps:propertyDefinition)"/>
      <assert
        test="($propDefCount = count(distinct-values(scps:propertyDefinition/scps:propertyName)))"
        flag="fatal" id="UD-004">[UD-004]- Dichiaraziane di proprieta' ripetuta; ogni proprieta'
        puo' essere dichiarata una sola volta.</assert>
      
      <assert
        test="(($periodOcc) and ($coordinatesOcc) and ($propDefCount &lt;= $propertyDefNum) and ($propDefCount &gt;= count(index-of($propNameOcc, '1')))) or (not($periodOcc) and ($coordinatesOcc) and ($propDefCount &lt;= $propertyDefNum) and ($propDefCount &gt;= (count(index-of($propNameOcc, '1')) - 2))) or (($periodOcc) and not($coordinatesOcc) and ($propDefCount &lt;= $propertyDefNum) and ($propDefCount &gt;= (count(index-of($propNameOcc, '1')) - 2))) or (not($periodOcc) and not($coordinatesOcc) and ($propDefCount &lt;= $propertyDefNum) and ($propDefCount &gt;= (count(index-of($propNameOcc, '1')) - 4)))"
        flag="fatal" id="UD-013">[UD-013]- Il numero di proprieta' dichiarate non e' coerente con la
        specifica (proprietà dichiarate: <value-of select="count(scps:propertyDefinition)"/>;
        numero massimo di proprietà ammesse: <value-of select="$propertyDefNum"/>.</assert>
    </rule>
    
    <rule context="//scps:propertyDefinition">
      <let name="propDefPosition" value="count(preceding-sibling::scps:propertyDefinition) + 1"/>
      <let name="pos" value="index-of(($propNameSet), normalize-space(scps:propertyName))"/>
      <let name="subPrNum" value="$dataTypeSet[$pos]"/>
      <let name="prName" value="normalize-space(scps:propertyName)"/>
      <assert
        test="not(contains(normalize-space($subPrNum), 'complex-')) or (number(substring-after(normalize-space($subPrNum), 'complex-')) &gt;= count(child::scps:subProperties/scps:propertyName))"
        flag="fatal" id="UD-022">[UD-022]- L'elenco delle sottoproprieta' non e' coerente con la
        specifica.</assert>
      <assert test="not(empty(index-of(($propNameSet), $prName)))" flag="fatal" id="UD-005"
        >[UD-005]- La proprieta' dichiarata (<value-of select="scps:propertyName"/>) non appartiene
        all'UrbanDataset.</assert>
      <assert
        test="empty($pos) or ((scps:dataType) and (normalize-space(scps:dataType) = normalize-space($dataTypeSet[$pos]))) or ((contains(normalize-space($subPrNum), 'complex-')) and (count(//scps:subProperties/scps:propertyName) &gt; 0))"
        flag="fatal" id="UD-006">[UD-006]- La dichiarazione della proprieta' non e' coerente con la
        sua specifica (dataType errato o sottoproprieta' assenti).</assert>
      <assert
        test="empty($pos) or (contains(normalize-space($subPrNum), 'complex-')) or (normalize-space(scps:unitOfMeasure) = normalize-space($umSet[$pos])) or not(empty(index-of($umAltSet, concat(scps:propertyName, '_', normalize-space(scps:unitOfMeasure)))))"
        flag="fatal" id="UD-007">[UD-007]- L'unita' di misura dichiarata per la proprieta' <value-of
          select="$prName"/> non e' coerente con la sua specifica.</assert>
      <assert
        test="empty($pos) or (normalize-space($codeListSet[$pos]) = 'null') or (normalize-space(scps:codeList) = normalize-space($codeListSet[$pos]))"
        flag="fatal" id="UD-021">[UD-021]- La proprieta' dovrebbe essere associata ad una lista di
        codici: la dichirazione della lista di codici e' assente o non coerente con la
        specifica.</assert>
      <assert
        test="empty($pos) or ((scps:measurementType) and (normalize-space($measurementTypeSet[$pos]) = 'false')) or ((not(scps:measurementType) and normalize-space($measurementTypeSet[$pos]) = 'false') or ((scps:measurementType) and normalize-space($measurementTypeSet[$pos]) = 'true'))"
        flag="fatal" id="UD-030">[UD-030]- Occorre specificare il metodo di misurazione applicato
        per calcolare le misure relative alla proprieta' <value-of select="$prName"/>.</assert>
      <assert
        test="not(scps:measurementType) or not(empty(index-of($measurementType, scps:measurementType)))"
        flag="fatal" id="UD-031">[UD-031]- Il metodo di misurazione indicato per la proprieta'
        <value-of select="$prName"/> non e' ammesso.</assert>
      <assert
        test="empty($pos) or not((scps:measurementType) and (normalize-space($measurementTypeSet[$pos]) = 'false'))"
        flag="fatal" id="UD-032">[UD-032]- E' stato indicato il metodo di misurazione per una
        proprieta' (<value-of select="scps:propertyName"/>) per cui non e' previsto.</assert>
      <assert
        test="($propDefPosition &gt; $mandatPropCount) or (count((/scps:UrbanDataset//scps:propertyDefinition[scps:propertyName = $propNameSet[$mandatPropPosition[$propDefPosition]]])) &gt;= 1) or (($propNameSet[$mandatPropPosition[$propDefPosition]] = 'start_ts') and not($periodCheck)) or (($propNameSet[$mandatPropPosition[$propDefPosition]] = 'end_ts') and not($periodCheck)) or (($propNameSet[$mandatPropPosition[$propDefPosition]] = 'latitude') and not($coordinatesCheck)) or (($propNameSet[$mandatPropPosition[$propDefPosition]] = 'longitude') and not($coordinatesCheck))"
        flag="fatal" id="UD-037">[UD-037]- Tutte le proprietà obbligatorie per l'UD devono essere
        dichiarate nel blocco propertyDefinition; proprieta' <value-of
          select="$propNameSet[$mandatPropPosition[$propDefPosition]]"/> assente.</assert>
      <assert
        test="empty(index-of(($propNameSet), $prName)) or (not(empty(index-of(tokenize($firstLevelPropNameList, '[,\s]+'), $prName))) or ($prName = 'coordinates') or ($prName = 'period') or ($prName = 'DataDescription')) or (count(/scps:UrbanDataset//scps:subProperties[scps:propertyName = $prName]) &gt; 0)"
        flag="fatal" id="UD-044">[UD-044]- Sottoproprietà <value-of select="$prName"/> dichiarata ma
        non collegata a nessuna proprietà composta (tutte le sottoproprietà ammesse per
        l'UrbanDataset devono essere collegate ad una proprietà, coerentemente con la
        specifica).</assert>
    </rule>
    
    <rule context="//scps:subProperties/scps:propertyName">
      <let name="prName" value="."/>
      <let name="pr"
        value="concat(ancestor::scps:subProperties/preceding-sibling::scps:propertyName, .)"/>
      <assert
        test="not(empty(index-of($subPropNameSet, $pr))) or (empty(index-of($propNameSet, ancestor::scps:subProperties/preceding-sibling::scps:propertyName)))"
        flag="fatal" id="UD-011">[UD-011]- Dichiarazione di sottoproprieta' non coerente con la
        specifica.</assert>
      <assert
        test="(empty(index-of($subPropNameSet, $pr))) or (count(/scps:UrbanDataset//scps:propertyDefinition[scps:propertyName = $prName]) &gt; 0)"
        flag="fatal" id="UD-043">[UD-043]- Dichiarazione di sottoproprieta' assente (una proprietà è
        stata indicata nella lista delle sottoproprietà di un'altra proprietà, ma la sua
        dichiarazione non è stata fornita).</assert>
    </rule>
    
    <rule context="//scps:line">
      <assert test="(count(preceding-sibling::scps:line) + $firstID) = number(./@id)" flag="warning"
        id="UD-020">[UD-020]- Attenzione: l'indentificatore della linea non segue una corretta
        numerazione progressiva.</assert>
      <assert
        test="(($useProfilePropCount = 0) and count(descendant::scps:property) = $propertyNum) or (count(descendant::scps:property) = $useProfilePropCount)"
        flag="fatal" id="UD-008">[UD-008]- Il numero di proprieta' fornite nella linea <value-of
          select="position()"/> non e' coerente con il blocco 'specification': se il blocco
        'specification/properties' è assente, le linee dell'UrbanDataset devono riportare tutte le
        proprietà previste a livello di specifica, altrimenti solo quelle scelte per il Profilo
        d'uso, ovvero quelle dichiarate nel blocco 'specification/properties'.</assert>
      <assert test="count(scps:property/@name) = count(distinct-values(scps:property/@name))"
        flag="fatal" id="UD-015">[UD-015]- Proprieta' ripetuta.</assert>
      <assert
        test="(empty(index-of($propNameSet, 'coordinates'))) or (scps:coordinates) or (($propNameOcc[index-of($propNameSet, 'coordinates')] = '0') and not($coordinatesCheck))"
        flag="fatal" id="UD-017">[UD-017]- Blocco 'coordinates' assente nella linea <value-of
          select="position()"/>: il blocco deve essere presente in ogni linea.</assert>
      <assert
        test="(empty(index-of($propNameSet, 'period'))) or (scps:period) or (($propNameOcc[index-of($propNameSet, 'period')] = '0') and not($periodCheck))"
        flag="fatal" id="UD-018">[UD-018]- Blocco 'period' assente nella linea <value-of
          select="position()"/>: il blocco deve essere presente in ogni linea.</assert>
      <assert
        test="(empty(index-of($propNameSet, 'DataDescription'))) or (scps:description) or (($propNameOcc[index-of($propNameSet, 'DataDescription')] = '0') and not($descrCheck))"
        flag="fatal" id="UD-023">[UD-023]- Blocco 'description' assente nella linea <value-of
          select="position()"/>: il blocco deve essere presente in ogni linea.</assert>
      <assert
        test="(empty(index-of($propNameSet, 'timestamp'))) or (scps:timestamp) or (($propNameOcc[index-of($propNameSet, 'timestamp')] = '0') and not($tsCheck))"
        flag="fatal" id="UD-045">[UD-045]- Blocco 'timestamp' assente nella linea <value-of
          select="position()"/>: il blocco deve essere presente in ogni linea.</assert>
      
      <assert
        test="($coordinatesOcc) or (not(empty(index-of($propNameSet, 'coordinates'))) and ($coordinatesCheck)) or not(scps:coordinates)"
        flag="fatal" id="UD-034">[UD-034]- Blocco 'coordinates' rilevato nella linea <value-of
          select="position()"/>: il blocco non e' ammesso per questa istanza.</assert>
      <assert
        test="($periodOcc) or (not(empty(index-of($propNameSet, 'period'))) and ($periodCheck)) or not(scps:period)"
        flag="fatal" id="UD-035">[UD-035]- Blocco 'period' rilevato nella linea <value-of
          select="position()"/>: il blocco non e' ammesso per questa istanza.</assert>
      <assert
        test="($descrOcc) or (not(empty(index-of($propNameSet, 'DataDescription'))) and ($descrCheck)) or not(scps:description)"
        flag="fatal" id="UD-036">[UD-036]- Blocco 'description' rilevato nella linea <value-of
          select="position()"/>: il blocco non e' ammesso per questa istanza.</assert>
      <assert
        test="($tsOcc) or (not(empty(index-of($propNameSet, 'timestamp'))) and ($tsCheck)) or not(scps:timestamp)"
        flag="fatal" id="UD-046">[UD-046]- Blocco 'timestamp' rilevato nella linea <value-of
          select="position()"/>: il blocco non e' ammesso per questa istanza.</assert>
      
      <assert
        test="not($coordinatesCheck) or not(scps:coordinates) or (($useProfilePropCount = 0) and (scps:coordinates/scps:height)) or (not($useProfilePropCount = 0) and ((not(scps:coordinates/scps:height) and not(//scps:propertyDefinition/scps:propertyName = 'height')) or ((scps:coordinates/scps:height) and (//scps:propertyDefinition/scps:propertyName = 'height'))))"
        flag="fatal" id="UD-040">[UD-040]- Incoerenza sull'utilizzo della proprieta' 'height' a
        livello di linea: se non e' stato dichiarato un Profilo d'uso, la proprieta' deve essere
        presente nella linea; altrimenti il suo utilizzo nella linea deve essere coerente con quanto
        dichiarato nel blocco 'specification/properties'.</assert>
      
      <assert
        test="not($coordinatesCheck) or not(scps:coordinates) or (($useProfilePropCount = 0) and (scps:coordinates/@format)) or (not($useProfilePropCount = 0) and ((not(scps:coordinates/@format) and not(//scps:propertyDefinition/scps:propertyName = 'format')) or ((scps:coordinates/@format) and (//scps:propertyDefinition/scps:propertyName = 'format'))))"
        flag="fatal" id="UD-041">[UD-041]- Incoerenza sull'utilizzo della proprieta' 'format' a
        livello di linea: se non e' stato dichiarato un Profilo d'uso, la proprieta' deve essere
        presente nella linea; altrimenti il suo utilizzo nella linea deve essere coerente con quanto
        dichiarato nel blocco 'specification/properties'.</assert>
    </rule>
    
    <rule context="//scps:property">
      <let name="pos" value="index-of(($propNameSet), normalize-space(@name))"/>
      <let name="propName" value="(normalize-space(@name))"/>
      <let name="subPrNum" value="$dataTypeSet[$pos]"/>
      <assert test="not(empty(index-of(($propNameSet), $propName)))" flag="fatal"
        id="UD-009">[UD-009]- La proprieta' <value-of select="@name"/> non appartiene
        all'UrbanDataset.</assert>
      
      <assert
        test="(.[ancestor::scps:property]) or (contains($firstLevelPropNameList, $propName))"
        flag="fatal" id="UD-019">[UD-019]- La proprieta' <value-of select="@name"/> non e' stata
        fornita in modo coerente con la specifica.</assert>
      <assert
        test="empty($pos) or (not(contains(normalize-space($subPrNum), 'complex-')) and (scps:val)) or ((contains(normalize-space($subPrNum), 'complex-')) and (count(child::scps:property) > 0))"
        flag="fatal" id="UD-012">[UD-012]- Il valore della proprieta' <value-of select="$propName"/> non
        e' fornito in modo corretto.</assert>
      
      <assert
        test="not(.[ancestor::scps:property]) or not(empty(index-of($subPropNameSet, normalize-space(concat(ancestor::scps:property/@name, $propName)))))"
        flag="fatal" id="UD-014">[UD-014]- Il valore della proprieta' <value-of select="$propName"/> non
        e' fornito in modo corretto.</assert>
      
      <assert test="count(scps:property/@name) = count(distinct-values(scps:property/@name))"
        flag="fatal" id="UD-016">[UD-016]- Sottoproprieta' ripetuta.</assert>
      
      <assert
        test="($propNameOcc[index-of($propNameSet, $propName)] = '1') or ($useProfilePropCount = 0) or (not(empty(index-of($useProfileProp, $propName))))"
        flag="fatal" id="UD-042">[UD-042] - La proprieta' <value-of select="$propName"/> non e'
        ammessa nella riga o perche' è una proprieta' di contesto o perche' non e' stata dichiarata
        nella sezione propertyDefinition.</assert>
    </rule>
  </pattern>
</schema>
